﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Counter1
{   
    /// <summary>
    /// 中缀表达式转换为后缀表达式
    /// </summary>
    class Compositor
    {
        private readonly string equation;

        //表达式栈
        private readonly Stack<char> opndStack = new Stack<char>();

        //操作符栈
        private readonly Stack<char> optrStack = new Stack<char>();

        public Compositor(string str)
        {
            equation = str;
        }

        /// <summary>
        /// 将合法的中缀表达式转换为后缀表达式
        /// </summary>
        /// <returns>后缀表达式的字符串</returns>
        public string Suffix()
        {
            string str = "";

            foreach (var c in equation)
            { //对中缀表达式字符串进行遍历筛选操作
                if (char.IsDigit(c) || c == '.')
                {//当前的字符是操作数  
                    opndStack.Push(c);
                    continue;
                }
                else
                {//当前字符不是操作数时添加分隔符
                    opndStack.Push('#');
                }
                //筛选操作符，
                //根据不同的优先级调整在操作符栈中的顺序。
                if (c == '(')
                {//当前字符是左括号   
                    optrStack.Push(c);
                    continue;
                }
                else if (c == ')')
                {//当前字符是右括号，将栈顶弹出，直到遇到左括号
                    while (optrStack.Count != 0 && optrStack.Peek() != '(')
                    {
                        opndStack.Push(optrStack.Pop());
                    }
                    if (optrStack.Count != 0)
                    {
                        optrStack.Pop();
                    }
                    else
                    {
                        Console.WriteLine("缺少左括号！");
                    }
                    continue;
                }
                else if (c == '+' || c == '-' || c == '*' || c == '/')
                {//当前字符是运算符
                    if (optrStack.Count == 0 || JudgeLevel(c, optrStack.Peek()) == '>')
                    {//若优先级大于栈顶运算符时，则把它压栈
                        optrStack.Push(c);
                    }
                    else if (JudgeLevel(c, optrStack.Peek()) == '<')
                    {//若优先级小于等于栈顶运算符时，将栈顶运算符弹出并输出，再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止，然后将该运算符压栈
                        while (optrStack.Count != 0 && JudgeLevel(c, optrStack.Peek()) == '<')
                        {
                            opndStack.Push(optrStack.Pop());
                        }
                        optrStack.Push(c);
                    }
                }
                else
                {//当前字符是未定义字符
                    Console.WriteLine("未知字符：" + c);
                    continue;
                }
            }

            while (optrStack.Count != 0)
            {//若各对象处理完毕，则把操作符栈中的运算符一并输出
                if (optrStack.Peek() != '(')
                {
                    opndStack.Push(optrStack.Pop());
                }
                else
                {
                    Console.WriteLine("缺少右括号！");
                    break;
                }
            }

            foreach (var c in opndStack)
            {//将后缀表达式栈复制为字符串
               str = c + str;
            }

            return str;
        }

        /// <summary>
        /// 判断当前运算符与栈顶运算符的优先级
        /// </summary>
        /// <param name="c">当前运算符</param>
        /// <param name="peek">栈顶运算符</param>
        /// <returns></returns>
        private char JudgeLevel(char c, char peek)
        {
            char optr = '<';
            if (c == '+' || c == '-')
            {
                if (peek == '*' || peek == '/')
                {
                    optr = '<';
                }
                else if (peek == '(')
                {
                    optr = '>';
                }
            }
            else if (c == '*' || c == '/')
            {
                if (peek == '+' || peek == '-' || peek == '(')
                {
                    optr = '>';
                }
            }
            return optr;
        }
    }
}
